#pragma once
#include <iostream>
#include <memory>

#include "Buffer.hpp"
#include "Socket.hpp"
#include "Channel.hpp"
#include "EventLoop.hpp"

enum ConStatus
{
    DISCONNECTED, // 连接关闭状态
    CONNECTING,   // 连接建立完成，待处理状态
    CONNECTED,    // 连接处理完成状态
    DISCONNECTING // 连接待关闭状态
};

class Connection;
using PtrConnection = std::shared_ptr<Connection>;

class Connection : public std::enable_shared_from_this<Connection>
{
private:
    int _conn_id;                  // 连接id与定时器任务id
    ConStatus _status;             // 连接状态
    bool _enable_inactive_release; // 是否启动非活跃连接销毁

    int _sockfd;      // 连接套接字文件描述符
    Socket _socket;   // 通信套接字对象
    Channel _channel; // 管理通信套接字文件描述符

    EventLoop *_loop;   // 关联的线程
    Buffer _in_buffer;  // 读取缓冲区
    Buffer _out_buffer; // 写入缓冲区

    using ConnectionCallback = std::function<void(const PtrConnection &cb)>;
    using MessageCallback = std::function<void(const PtrConnection &cb, Buffer *)>;
    using ClosedCallback = std::function<void(const PtrConnection &cb)>;
    using AnyEventCallback = std::function<void(const PtrConnection &cb)>;

    // 用户传入的回调函数
    ConnectionCallback _connection_callback; 
    MessageCallback _message_callback;
    ClosedCallback _closed_callback;
    AnyEventCallback _anyevent_callback;
    // 组件内部关闭连接时的回调函数
    ClosedCallback _server_closed_callback;

    // 读事件就绪的回调函数
    void HandleRead()
    {
        char buf[65535];
        ssize_t ret = _socket.RecvNonBlock(buf, 65535);
        if (ret < 0)
            return ShutdownInLoop();
        // 将读取的数据放入读取缓冲区中
        _in_buffer.WriteAndMove(buf, ret);
        if (_in_buffer.ReadAbleSize() > 0)
            _message_callback(shared_from_this(), &_in_buffer);
    }
    void HandleWrite()
    {
        ssize_t ret = _socket.SendNonBlock(_out_buffer.ReadPoistion(), _out_buffer.ReadAbleSize());
        if (ret < 0)
        {
            if (_in_buffer.ReadAbleSize() > 0)
                _message_callback(shared_from_this(), &_in_buffer);
            return Release();
        }
        // 从缓冲区读和写入缓冲区可以直接移动指针，但是从缓冲区把数据发送出去不可以
        _out_buffer.MoveWriteIndex(ret);
        // 如果发送缓冲区没有数据了，那么可以关闭写事件监控
        if (_out_buffer.ReadAbleSize() == 0)
        {
            _channel.DisableWrite();
            //如果连接是待关闭状态，释放连接即可
            if (_status == DISCONNECTING)
                Release();
        }
    }
    void HandleError()
    {
        HandleClose();
    }
    void HandleClose()
    {
        //如果读取缓冲区中有数据，先读取出来，后关闭连接
        if(_in_buffer.ReadAbleSize() > 0)
            _message_callback(shared_from_this(), &_in_buffer);
        Release();
    }
    void HandleEvent()
    {
        //刷新定时任务
        if(_enable_inactive_release)
            _loop->TimerRefresh(_conn_id);
        if(_anyevent_callback) 
            _anyevent_callback(shared_from_this());
    }

    //对链接进行初始化的接口
    void EstablishedInLoop()
    {
        //修改连接状态
        assert(_status == CONNECTED);
        _status = CONNECTED;
        //启动读事件监控
        _channel.EnableRead();
        //调用回调函数
        if(_connection_callback)
            _connection_callback(shared_from_this());
    }
    //将数据放入发送缓冲区，启动写事件监控函数，并非真的发送数据
    void SendInLoop(Buffer &buf)
    {
        if(_status == DISCONNECTING)
            return;
        //将数据写入发送缓冲区
        _out_buffer.WriteBufferAndMove(_out_buffer);
        //启动写事件监控
        if(_channel.WriteAble() == false)
            _channel.EnableWrite();
    }
    //关闭非实际的连接释放操作
    void ShutdownInLoop()
    {
        _status = DISCONNECTING;
        //如果读取缓冲区中有数据，先读取出来
        if(_in_buffer.ReadAbleSize() > 0)
            _message_callback(shared_from_this(), &_in_buffer);

        if(_out_buffer.ReadAbleSize() > 0)
        {
            if(_channel.WriteAble() == false)
                _channel.EnableWrite();
        }
        if(_out_buffer.ReadAbleSize() == 0)
            Release();
        
    }
    //实际关闭连接的接口
    void ReleaseInLoop()
    {
        _status = DISCONNECTED;
        _channel.Remove();
        _socket.Close();
        //判断时间轮中还有没有该任务没有执行,有的话则关闭
        if(_loop->HasTiemrTask(_conn_id))
            CancelactiveReleaseInLoop();
        if(_closed_callback) 
            _closed_callback(shared_from_this());
        if(_server_closed_callback)
            _server_closed_callback(shared_from_this());
    }
    void EnableInactiveReleaseInLoop(int sec)
    {
        _enable_inactive_release = true;
        //如果存在该任务的话，刷新一下
        if(_loop->HasTiemrTask(_conn_id))    
            _loop->TimerRefresh(_conn_id);
        
        //如果不存在，则新增一个定时任务
        _loop->TimerAdd(_conn_id, sec, std::bind(&Connection::Release, this));
    }
    void CancelactiveReleaseInLoop()
    {
        _enable_inactive_release = false;
        //如果存在该任务的话, 取消定时任务
        if(_loop->HasTiemrTask(_conn_id))    
            _loop->TimerCancel(_conn_id);
    }

public:
    Connection(int conn_id, int sockfd, EventLoop *loop)
        : _conn_id(conn_id), _enable_inactive_release(false), _sockfd(sockfd), _loop(loop), _channel(_loop, _sockfd)
    {
        _channel.SetReadCallBack(std::bind(&Connection::HandleRead, this));
        _channel.SetWriteCallBack(std::bind(&Connection::HandleWrite, this));
        _channel.SetErrorCallBack(std::bind(&Connection::HandleError, this));
        _channel.SetCloseCallBack(std::bind(&Connection::HandleClose, this));
        _channel.SetEventCallBack(std::bind(&Connection::HandleEvent, this));
    }
    ~Connection() = default;

    // 获取私有成员
    int Fd() { return _sockfd; }
    int Id() { return _conn_id; }
    // 判断是否处于CONNECTED状态
    bool IsConnected() { return _status == CONNECTED; }

    // 设置各种事件回调函数
    void SetConnectionCallback(const ConnectionCallback &cb) { _connection_callback = cb; }
    void SetMessageCallback(const MessageCallback &cb) { _message_callback = cb; }
    void SetClosedCallback(const ClosedCallback &cb) { _closed_callback = cb; }
    void SetAnyEventCallback(const AnyEventCallback &cb) { _anyevent_callback = cb; }
    void SetServerClosedCallback(const ClosedCallback &cb) { _server_closed_callback = cb; }

    void Established()
    {
        _loop->RunInLoop(std::bind(&Connection::EstablishedInLoop, this));
    }
    // 发送数据
    void Send(const char *data, size_t len)
    {
        //data可能是个临时空间，我们发送的操作是放入任务队列，而并非立即执行
        //可能我们执行的时候，data空间已经被释放了
        Buffer buf;
        buf.WriteAndMove(data, len);
        _loop->RunInLoop(std::bind(&Connection::SendInLoop, this, buf));
    }
    // 提供给组件使用者的关闭接口--并不直接关闭，需要判断有没有数据待处理
    void Shutdown()
    {
        _loop->RunInLoop(std::bind(&Connection::ShutdownInLoop, this));
    }
    void Release()
    {
        _loop->QueuePushInLoop(std::bind(&Connection::ReleaseInLoop, this));
    }
    // 启动非活跃连接定时销毁
    void EnableInactiveRelease(int sec)
    {
        _loop->RunInLoop(std::bind(&Connection::EnableInactiveReleaseInLoop, this, sec));
    }
    // 关闭非活跃连接定时销毁
    void CancelactiveRelease(int sec)
    {
        _loop->RunInLoop(std::bind(&Connection::CancelactiveReleaseInLoop, this));
    }
};